<script setup lang="tsx">
// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 模块导入 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

import { NButton } from 'naive-ui';
import type { Ref } from 'vue';
import { nextTick, ref } from 'vue';
import dayjs from 'dayjs';
import axios from 'axios';
import { useAppStore } from '@/store/modules/app';
import { useAuth } from '@/hooks/business/auth';
import { useTable, useTableOperate } from '@/hooks/common/table';
import { $t } from '@/locales';
import { transDeleteParams } from '@/utils/common';
import { fetchDeleteCjRecord, fetchGetCjRecordPage } from '@/service/api';
import { useDict } from '@/hooks/business/dict';
import type { FlatResponseData } from '~/packages/axios/src';
import { localStg } from '@/utils/storage';
import { useBoolean } from '~/packages/hooks/src';
import RecordSearch from './modules/record-search.vue';
import type { OperateType } from './modules/record-operate-drawer.vue';
import RecordOperateDrawer from './modules/record-operate-drawer.vue';
import RecordBindProjectModal from './modules/record-bind-project-modal.vue';

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 组件名称 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

defineOptions({
  name: 'CjRecordPage'
});

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 组合式函数 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

const appStore = useAppStore();

const { hasAuth } = useAuth();

const { dictTag, dictLabel } = useDict();

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 父子传参 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 框架模型 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

const operateType = ref<OperateType>('add');

const editingData: Ref<Api.Sampling.Record | null> = ref(null);

const { columns, columnChecks, resetAllColumns, data, loading, getData, getDataByPage, mobilePagination, searchParams, resetSearchParams } = useTable(
  {
    apiFn: (params: Api.Sampling.RecordSearchParams): Promise<FlatResponseData<Api.Common.PaginatingQueryRecord<Api.Sampling.Record>>> => {
      return new Promise((resolve, reject) => {
        fetchGetCjRecordPage(params)
          .then(res => {
            if (!res.error && res.data) {
              // 修正某些列按值自适应
              res.data.records.forEach((item: Api.Sampling.Record) => {
                item.orgName = `${item.provinceCityCountyInfo?.provinceName}${item.provinceCityCountyInfo?.cityName}${item.provinceCityCountyInfo?.countyName}`;
              });
              // 自适应列
              nextTick(() => {
                updateColumnsWidth(res.data);
              });
              resolve(res);
            }
          })
          .catch(err => reject(err));
      });
    },
    showTotal: true,
    apiParams: {
      page: 1,
      pageSize: 20,
      projectId: '',
      year: '',
      taskStatus: '',
      provinceName: '',
      cityName: '',
      town: ''
    },
    columns: () => [
      {
        type: 'selection',
        align: 'center',
        width: 48,
        fixed: 'left'
      },
      {
        key: 'index',
        title: $t('common.index'),
        width: 64,
        align: 'center',
        fixed: 'left'
      },
      {
        key: 'projectName',
        title: $t('page.sampling.task.projectId'),
        align: 'left',
        titleAlign: 'center',
        width: 77,
        fixed: 'left'
      },
      {
        key: 'code',
        title: $t('page.sampling.task.code'),
        align: 'left',
        titleAlign: 'center',
        width: 77,
        fixed: 'left'
      },
      {
        key: 'year',
        title: $t('page.sampling.task.year'),
        align: 'center',
        titleAlign: 'center',
        width: 77,
        fixed: 'left'
      },
      {
        key: 'positionType',
        title: $t('page.sampling.task.positionType'),
        align: 'center',
        titleAlign: 'center',
        width: 77,
        fixed: 'left',
        render: row => dictLabel('cj_position_type', row.positionType)
      },
      {
        key: 'taskStatus',
        title: $t('page.sampling.task.taskStatus'),
        align: 'center',
        titleAlign: 'center',
        width: 130,
        fixed: 'left',
        render: row => dictTag('cj_task_status', row.taskStatus)
      },
      {
        key: 'samplingType',
        title: $t('page.sampling.task.samplingType'),
        align: 'center',
        titleAlign: 'center',
        width: 101,
        render: row => dictLabel('cj_sampling_type', row.samplingType)
      },
      {
        key: 'orgName',
        title: $t('page.sampling.task.orgId'),
        align: 'left',
        titleAlign: 'center',
        width: 77
      },
      {
        key: 'provinceName',
        title: $t('page.sampling.task.province'),
        titleAlign: 'center',
        align: 'center',
        width: 34
      },
      {
        key: 'cityName',
        title: $t('page.sampling.task.city'),
        align: 'center',
        titleAlign: 'center',
        width: 34
      },
      {
        key: 'countyName',
        title: $t('page.sampling.task.county'),
        align: 'center',
        titleAlign: 'center',
        width: 49
      },
      {
        key: 'autoLngLat',
        title: $t('page.sampling.record.autoLngLat'),
        align: 'center',
        width: 77,
        render: row => (row.autoLngLat ? $t('common.yesOrNo.yes') : $t('common.yesOrNo.no'))
      },
      {
        key: 'wgs84Longitude',
        title: $t('page.sampling.task.wgs84Longitude'),
        align: 'right',
        titleAlign: 'center',
        width: 49
      },
      {
        key: 'wgs84Latitude',
        title: $t('page.sampling.task.wgs84Latitude'),
        align: 'right',
        titleAlign: 'center',
        width: 49
      },
      {
        key: 'wgs84Altitude',
        title: $t('page.sampling.task.wgs84Altitude'),
        align: 'right',
        titleAlign: 'center',
        width: 49
      },
      {
        key: 'screenLongitude',
        title: $t('page.sampling.record.screenLongitude'),
        align: 'right',
        titleAlign: 'center',
        width: 77
      },
      {
        key: 'screenLatitude',
        title: $t('page.sampling.record.screenLatitude'),
        align: 'right',
        titleAlign: 'center',
        width: 77
      },
      {
        key: 'screenAltitude',
        title: $t('page.sampling.record.screenAltitude'),
        align: 'right',
        titleAlign: 'center',
        width: 77
      },
      {
        key: 'samplingTime',
        title: $t('page.sampling.record.samplingTime'),
        align: 'center',
        titleAlign: 'center',
        width: 158,
        render: row => dayjs(row.samplingTime).format('YYYY-MM-DD HH:mm:ss')
      },
      {
        key: 'operate',
        title: $t('common.operate'),
        align: 'center',
        width: 120,
        fixed: 'right',
        render: row => (
          <div class="flex-center gap-8px">
            <NButton
              type="primary"
              quaternary
              size="small"
              onClick={() => {
                handleView(row);
              }}
            >
              查看
            </NButton>
            {hasAuth('cj:record:auth') && (
              <NButton
                type="primary"
                quaternary
                size="small"
                onClick={() => {
                  handleAuth(row);
                }}
              >
                审核
              </NButton>
            )}
          </div>
        )
      }
    ]
  }
);

const { drawerVisible, openDrawer, checkedRowKeys, onBatchDeleted } = useTableOperate(data, getData);

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 业务模型 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

const { bool: bindProjectModalVisible, setTrue: showBindProjectModal } = useBoolean();

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 框架方法 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

function handleAdd() {
  operateType.value = 'add';
  openDrawer();
}

// function edit(item: Api.Sampling.Record) {
//   operateType.value = 'edit';
//   editingData.value = { ...item };
//   openDrawer();
// }

// async function handleDelete(id: string) {
//   const { error, data: result } = await fetchDeleteCjRecord(transDeleteParams([id]));
//   if (!error && result) {
//     await onDeleted();
//   }
// }

async function handleBatchDelete() {
  const { error, data: result } = await fetchDeleteCjRecord(transDeleteParams(checkedRowKeys.value));
  if (!error && result) {
    await onBatchDeleted();
  }
}

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 业务方法 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

function handleView(item: Api.Sampling.Record) {
  operateType.value = 'view';
  editingData.value = { ...item };
  openDrawer();
}

function handleAuth(item: Api.Sampling.Record) {
  operateType.value = 'auth';
  editingData.value = { ...item };
  openDrawer();
}

/** 计算动态列宽 */

// 简单列名数组
const simpleCols: string[] = [
  'projectName',
  'code',
  'orgName',
  'provinceName',
  'cityName',
  'countyName',
  'wgs84Longitude',
  'wgs84Latitude',
  'wgs84Altitude',
  'screenLongitude',
  'screenLatitude',
  'screenAltitude'
];
// 表格滚动宽度
const tableScrollWidth = ref<number>(962);
// 原始列宽
let originColWidths: any = {};
// 动态列宽字典
let dynamicColWidths: any = {};
// 是否初始化原始列宽
let originColWidthsInited = false;
// 临时页面元素
let tempDiv: any = null;
let tempSpan: any = null;
// 临时滚动宽度
let tempScrollWidth: number = 0;
// 创建临时页面元素
function createSpan() {
  const wrapper = document.createElement('div');
  wrapper.style.visibility = 'hidden';
  wrapper.style.whiteSpace = 'nowrap';
  wrapper.style.overflow = 'hidden';
  const span = document.createElement('span');
  span.style.visibility = 'visible';
  span.style.display = 'inline-block';
  wrapper.appendChild(span);
  tempDiv = wrapper;
  tempSpan = span;
  const firstHeader = document.getElementsByClassName('n-data-table-th__title')[0];
  firstHeader.appendChild(tempDiv);
}
// 计算文本宽度
function calcTextWidth(content: string): number {
  tempSpan.textContent = content;
  return tempSpan.offsetWidth;
}
// 计算列宽
function calcColWidth(col: any, content: string) {
  if (simpleCols.includes(col.key)) {
    if (!originColWidthsInited) {
      originColWidths[col.key] = col.width;
    }
    const w = calcTextWidth(content) + 20;
    dynamicColWidths[col.key] = Math.max(dynamicColWidths[col.key] || 0, w);
  }
}
// 更新动态列宽和表格滚动宽度
function setCalcWidth(column: any) {
  if (dynamicColWidths[column.key]) {
    column.width = Math.max(originColWidths[column.key], dynamicColWidths[column.key]);
  }
  tempScrollWidth += column.width;
}
// 更新列宽
function updateColumnsWidth(rows: any) {
  // 重置相关变量
  if (!tempDiv) {
    createSpan();
  }
  if (!originColWidthsInited) {
    originColWidths = {};
  }
  dynamicColWidths = {};
  tempScrollWidth = 0;
  const tempColumns = [...columns.value];
  // 计算列宽
  rows.records.forEach((row: any) => {
    tempColumns.forEach((column: any) => {
      if (!column.children) {
        calcColWidth(column, `${row[column.key]}`);
      } else {
        column.children.forEach((child1: any) => {
          if (!child1.children) {
            calcColWidth(child1, `${row[child1.key]}`);
          } else {
            child1.children.forEach((child2: any) => {
              calcColWidth(child2, `${row[child2.key]}`);
            });
          }
        });
      }
    });
  });
  // 更新宽度
  tempColumns.forEach((column: any) => {
    if (!column.children) {
      setCalcWidth(column);
    } else {
      column.children.forEach((child1: any) => {
        if (!child1.children) {
          setCalcWidth(child1);
        } else {
          child1.children.forEach((child2: any) => {
            setCalcWidth(child2);
          });
        }
      });
    }
  });
  // 重置滚动宽度，重新加载 columns
  tableScrollWidth.value = tempScrollWidth + 1;
  resetAllColumns(() => tempColumns);
  originColWidthsInited = true;

  // 移除临时元素
  if (tempDiv.parentNode) {
    tempDiv.parentNode.removeChild(tempDiv);
    tempDiv = null;
    tempSpan = null;
  }
}

function handleExportData() {
  const baseUrl = import.meta.env.VITE_SERVICE_BASE_URL;
  axios({
    method: 'get',
    headers: {
      authorization: `Bearer ${localStg.get('token')}`,
      'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
    },
    url: `${baseUrl}/cj_record/export_data`,
    data: searchParams,
    responseType: 'blob'
  }).then(response => {
    if (response.status === 200) {
      const blob = response.data;
      downloadFile('采样记录.xlsx', blob);
    }
  });
}

function downloadFile(fileName: string, blob: any) {
  const aLink = document.createElement('a');
  // const blob = blob; // new Blob([content]);
  const evt = document.createEvent('HTMLEvents');
  // Loss last two parameters, an error is reported in FF,
  // 1. Event Type 2. Bubbling or not 3. Whether to block the browser's default behavior.
  evt.initEvent('click', true, true);
  aLink.download = fileName;
  aLink.href = URL.createObjectURL(blob);
  // Compatible with firefox
  aLink.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
}

function handleBindProject() {
  showBindProjectModal();
}

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 框架生命周期 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 业务生命周期 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++
</script>

<template>
  <div class="min-h-500px flex-col-stretch gap-8px overflow-hidden lt-sm:overflow-auto">
    <RecordSearch v-model:model="searchParams" @reset="resetSearchParams" @search="getDataByPage" />
    <NCard :bordered="false" class="sm:flex-1-hidden card-wrapper" content-class="flex-col">
      <TableHeaderOperation
        v-model:columns="columnChecks"
        :checked-row-keys="checkedRowKeys"
        :loading="loading"
        add-auth="cj:record:add"
        delete-auth="cj:record:delete"
        @add="handleAdd"
        @delete="handleBatchDelete"
        @refresh="getData"
      >
        <template #suffix>
          <template v-if="hasAuth('cj:record:exportData')">
            <NButton type="primary" size="small" ghost @click="handleExportData">
              <template #icon>
                <icon-material-symbols:export-notes class="text-icon" />
              </template>
              导出数据
            </NButton>
          </template>
          <template v-if="hasAuth('cj:record:bindProject')">
            <NButton type="primary" size="small" ghost :disabled="!(checkedRowKeys?.length > 0)" @click="handleBindProject">
              <template #icon>
                <icon-tabler:circles-relation class="text-icon" />
              </template>
              关联项目
            </NButton>
          </template>
        </template>
      </TableHeaderOperation>
      <NDataTable
        v-model:checked-row-keys="checkedRowKeys"
        remote
        striped
        size="small"
        class="sm:h-full"
        :data="data"
        :scroll-x="tableScrollWidth"
        :columns="columns"
        :flex-height="!appStore.isMobile"
        :loading="loading"
        :single-line="false"
        :row-key="row => row.id"
        :pagination="mobilePagination"
      />
      <RecordOperateDrawer v-model:visible="drawerVisible" :operate-type="operateType" :row-data="editingData" @submitted="getDataByPage" />
      <RecordBindProjectModal v-model:visible="bindProjectModalVisible" :record-ids="checkedRowKeys" @submitted="getData" />
    </NCard>
  </div>
</template>
